<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="CKXEe" id="CKXEe"><span data-lake-id="u3b7f90e1" id="u3b7f90e1">典型回答</span></h1>
  <h2 data-lake-id="earkQ" id="earkQ"><span data-lake-id="udff7f7a0" id="udff7f7a0">三次握手</span></h2>
  <p data-lake-id="u05642edf" id="u05642edf"><br></p>
  <p data-lake-id="u3990f88a" id="u3990f88a"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1675138505949-2e21fdde-ec4c-4943-82da-96a85391642c.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_25%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ub3b5fb23" id="ub3b5fb23"><br></p>
  <ol list="u997b106b">
   <li fid="uff441917" data-lake-id="ad61d4df29f1607417c01654180cab6a_li_2" id="ad61d4df29f1607417c01654180cab6a_li_2"><span data-lake-id="u863904b7" id="u863904b7">你（客户端）给一个朋友（服务器）打电话，告诉他你想开始对话。这就像是发送一个SYN（同步序列编号）信号，表示你想开始建立连接。</span><span data-lake-id="u218e7326" id="u218e7326" style="background-color: #E7E9E8">（client向server发送syn，seq=x，此时client验证client发送能力正常。client置为SYN_SENT状态）</span></li>
   <li fid="uff441917" data-lake-id="6d2a9ca8da3e45e05d9a62999c84238b_li_3" id="6d2a9ca8da3e45e05d9a62999c84238b_li_3"><span data-lake-id="u7315d7ba" id="u7315d7ba">你的朋友接到电话，明白你想开始对话。他回应说“好的，我准备好了”，同时也告诉你他也想说些话。这就相当于服务器发送SYN-ACK（同步和确认）信号，既确认收到了你的请求，也表明它准备好了并想建立连接。</span><span data-lake-id="u55e90eb7" id="u55e90eb7" style="background-color: #E7E9E8">（server收到syn，此时server验证client发送能力正常，server接收能力正常。server向client发送ack = x + 1,seq = y，此时server验证server发送能力正常。server置为SYN_RCVD状态）</span></li>
   <li fid="uff441917" data-lake-id="u916cb209" id="u916cb209"><span data-lake-id="u52656172" id="u52656172">最后，你回复你的朋友说你收到了他的确认，现在可以开始对话了。这就是发送ACK（确认）信号，确认你已经准备好进行通信。</span><span data-lake-id="u8aeaf8e7" id="u8aeaf8e7" style="background-color: #E7E9E8">（client收到ack，此时client验证client接收能力正常，server接收发送能力正常。client向server发送ack = y + 1， seq = x + 1，server接收到后验证client接收能力正常。client置为ESTABLISHED状态）</span></li>
  </ol>
  <h2 data-lake-id="bkBoF" id="bkBoF"><span data-lake-id="ub3863ad0" id="ub3863ad0">四次挥手</span></h2>
  <p data-lake-id="uf85cb1ca" id="uf85cb1ca"><br></p>
  <p data-lake-id="u8020b053" id="u8020b053"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1675138535863-b4e954fa-ddff-4d1c-b1eb-195c98906c86.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_26%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u747ec089" id="u747ec089"><br></p>
  <ol list="u1b178b25">
   <li fid="u9eee8c56" data-lake-id="44e869bb2b8f17404ddad452d75e0be8_li_5" id="44e869bb2b8f17404ddad452d75e0be8_li_5"><span data-lake-id="u18bb1fa8" id="u18bb1fa8">你（客户端）和朋友（服务器）通话结束后，告诉他你想挂电话了。这就像是发送一个FIN（结束）信号，表示你想结束这次连接。</span><span data-lake-id="ub8164531" id="ub8164531" style="background-color: #E7E9E8">（client向server发送fin。client置为FIN_WAIT_1）</span></li>
   <li fid="u9eee8c56" data-lake-id="a1142a75042337197dff856af86df15a_li_6" id="a1142a75042337197dff856af86df15a_li_6"><span data-lake-id="u88469356" id="u88469356">朋友听到你想挂电话了，他回应说“知道了，但我还有点事情要处理”，即使他知道对话即将结束。这就相当于服务器发送ACK（确认）信号，确认收到了你想结束连接的请求，但可能还需要一些时间来处理剩余的数据。</span><span data-lake-id="ud97a380d" id="ud97a380d" style="background-color: #E7E9E8">（server向client发送ack。server置为CLOSE_WAIT，client置为FIN_WAIT_2）</span></li>
   <li fid="u9eee8c56" data-lake-id="e69146501c580335400671a4ceb1bfce_li_7" id="e69146501c580335400671a4ceb1bfce_li_7"><span data-lake-id="u3ccbc307" id="u3ccbc307">一段时间后，你的朋友处理完了他的事情，这时他打电话告诉你他也准备好挂电话了。这是服务器端发送第二个FIN信号，表明他现在也准备好结束这次连接。</span><span data-lake-id="ud34caf0e" id="ud34caf0e" style="background-color: #E7E9E8">（等server传输数据完毕后，向client发送fin。server置为LAST_ACK）</span></li>
   <li fid="u9eee8c56" data-lake-id="c1256c70cceb1cc9a715e4c2354d3cf7_li_8" id="c1256c70cceb1cc9a715e4c2354d3cf7_li_8"><span data-lake-id="uaf6802fa" id="uaf6802fa">最后，你回复说你收到了他的消息，并同意现在可以挂电话了。这就是发送最后一个ACK信号，确认收到服务器端的结束请求。</span><span data-lake-id="ue5c93a83" id="ue5c93a83" style="background-color: #E7E9E8">（client向server发送ack。client置为TIME_WAIT。之后等待2MSL，client关闭。server接收到后置为CLOSED）</span></li>
  </ol>
  <p data-lake-id="u5bc3db9a" id="u5bc3db9a"><span data-lake-id="ue5fd03ad" id="ue5fd03ad">​</span><br></p>
  <blockquote data-lake-id="u773e6509" id="u773e6509">
   <p data-lake-id="u760dd2e9" id="u760dd2e9"><span data-lake-id="u7d6712fa" id="u7d6712fa">其中等待2倍的最大报文段生存时间（2MSL，Maximum Segment Lifetime）是为了确保在网络中的所有剩余数据报文段都被丢弃，以防止旧的数据报文段在之后的连接中引发混淆或冲突。</span></p>
  </blockquote>
  <h1 data-lake-id="dtN46" id="dtN46"><span data-lake-id="uddb41247" id="uddb41247">知识扩展</span></h1>
  <p data-lake-id="u23485965" id="u23485965"><br></p>
  <h2 data-lake-id="rBIvE" id="rBIvE"><span data-lake-id="u827152e9" id="u827152e9">为啥三次握手</span></h2>
  <p data-lake-id="d3d0a9563a43c516d781aeb1bfcd172e_p_54" id="d3d0a9563a43c516d781aeb1bfcd172e_p_54"><span data-lake-id="u015dfdc9" id="u015dfdc9">TCP三次握手验证了client和server的收包和发包能力。</span></p>
  <p data-lake-id="ud0b9543a" id="ud0b9543a" style="text-align: justify"><br></p>
  <p data-lake-id="ue14f37f3" id="ue14f37f3" style="text-align: justify"><span data-lake-id="u2302319c" id="u2302319c" style="color: inherit">第一次握手：客户端发送网络包，服务端收到了。这样服务端就能得出结论：</span><strong><span data-lake-id="u748fb1f7" id="u748fb1f7" style="color: inherit">客户端的发送能力、服务端的接收能力是正常的。</span></strong></p>
  <p data-lake-id="ud7096123" id="ud7096123" style="text-align: justify"><strong><span data-lake-id="u68e00651" id="u68e00651" style="color: inherit">​</span></strong><br></p>
  <p data-lake-id="ud84612ad" id="ud84612ad" style="text-align: justify"><span data-lake-id="u57cbca63" id="u57cbca63" style="color: inherit">第二次握手：服务端发包，客户端收到了。</span><strong><span data-lake-id="ufec59c9a" id="ufec59c9a" style="color: inherit">这样客户端就能得出结论：服务端的接收、发送能力，客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。</span></strong></p>
  <p data-lake-id="u414ec555" id="u414ec555" style="text-align: justify"><span data-lake-id="u85012b69" id="u85012b69" style="color: inherit">​</span><br></p>
  <p data-lake-id="u036c8da9" id="u036c8da9" style="text-align: justify"><span data-lake-id="u9b64a880" id="u9b64a880" style="color: inherit">第三次握手：客户端发包，服务端收到了。</span><strong><span data-lake-id="uc2e51f2e" id="uc2e51f2e" style="color: inherit">这样服务端就能得出结论：客户端的接收、发送能力正常，服务器自己的发送、接收能力也正常。</span></strong></p>
  <p data-lake-id="u5c173bdb" id="u5c173bdb" style="text-align: justify"><strong><span data-lake-id="u484a9e6e" id="u484a9e6e" style="color: inherit">​</span></strong><br></p>
  <p data-lake-id="u6dd159b3" id="u6dd159b3" style="text-align: justify"><span data-lake-id="u40ad4e42" id="u40ad4e42" style="color: inherit">所以，只有</span><strong><span data-lake-id="ueca22a68" id="ueca22a68" style="color: inherit">三次握手才能确认双方的接收与发送能力是否正常。</span></strong></p>
  <p data-lake-id="ubad86e6d" id="ubad86e6d"><span data-lake-id="u6a894b38" id="u6a894b38">​</span><br></p>
  <p data-lake-id="u673f57e4" id="u673f57e4"><span data-lake-id="u5b094806" id="u5b094806" style="color: rgb(62, 62, 62)">如果是两次握手，服务端无法确定客户端是否已经接收到了自己发送的初始序列号，如果第二次握手报文丢失，那么客户端就无法知道服务端的初始序列号，那 TCP 的可靠性就无从谈起。</span></p>
  <p data-lake-id="u83e2a0d4" id="u83e2a0d4"><br></p>
  <p data-lake-id="ua084555a" id="ua084555a"><span data-lake-id="u5eaac016" id="u5eaac016">客户端由于某种原因发送了两个不同序号的 SYN 包，我们知道网络环境是复杂的，旧的数据包有可能先到达服务器。如果是两次握手，服务器收到旧的 SYN 就会立刻建立连接，那么会造成网络异常。</span></p>
  <p data-lake-id="u6c31cf1d" id="u6c31cf1d"><span data-lake-id="u683689da" id="u683689da">​</span><br></p>
  <p data-lake-id="u807cb688" id="u807cb688"><span data-lake-id="u074bf79b" id="u074bf79b">如果是三次握手，服务器需要回复</span><span data-lake-id="u3582531a" id="u3582531a"> </span><span data-lake-id="u634eaa9a" id="u634eaa9a">SYN+ACK</span><span data-lake-id="u4efe5cf9" id="u4efe5cf9"> </span><span data-lake-id="udc6123e5" id="udc6123e5">包，客户端会对比应答的序号，如果发现是旧的报文，就会给服务器发</span><span data-lake-id="u0aad7dd8" id="u0aad7dd8"> </span><span data-lake-id="ua8d88b29" id="ua8d88b29">RST</span><span data-lake-id="u6dda6599" id="u6dda6599"> </span><span data-lake-id="ueb8be327" id="ueb8be327">报文，直到正常的</span><span data-lake-id="u2188eaa1" id="u2188eaa1"> </span><span data-lake-id="ub7b71eeb" id="ub7b71eeb">SYN</span><span data-lake-id="u5aa201ae" id="u5aa201ae"> </span><span data-lake-id="ud5e9aa00" id="ud5e9aa00">到达服务器后才正常建立连接。</span></p>
  <p data-lake-id="uc92f4d7f" id="uc92f4d7f"><span data-lake-id="u431ec489" id="u431ec489">​</span><br></p>
  <p data-lake-id="uba49369c" id="uba49369c"><span data-lake-id="ubbf9900c" id="ubbf9900c">所以三次握手才有足够的上下文信息来判断当前连接是否是历史连接。</span></p>
  <h2 data-lake-id="wpou9" id="wpou9"><span data-lake-id="u4304efe6" id="u4304efe6">为啥四次挥手</span></h2>
  <p data-lake-id="ub29411da" id="ub29411da"><span data-lake-id="u44265989" id="u44265989">其实在 TCP 握手的时候，接收端发送 SYN+ACK 的包是将一个 ACK 和一个 SYN 合并到一个包中，所以减少了一次包的发送，三次完成握手。</span></p>
  <p data-lake-id="u26c05795" id="u26c05795"><span data-lake-id="u41a334d0" id="u41a334d0">​</span><br></p>
  <p data-lake-id="u429dc85f" id="u429dc85f"><span data-lake-id="u345879e1" id="u345879e1">对于四次挥手，因为</span><strong><span data-lake-id="u3b7c4fee" id="u3b7c4fee"> TCP 是全双工通信</span></strong><span data-lake-id="ucfc6b6d3" id="ucfc6b6d3">，在主动关闭方发送 FIN 包后，接收端可能还要发送数据，不能立即关闭服务器端到客户端的数据通道，所以也就不能将服务器端的 FIN 包与对客户端的 ACK 包合并发送，只能先确认 ACK，然后服务器待无需发送数据时再发送 FIN 包，所以四次挥手时必须是四次数据包的交互。</span></p>
 </body>
</html>